home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Documentation / Tech Notes & Articles / Recipes / Data Interchange / Promises < prev    next >
Encoding:
Text File  |  1995-12-08  |  8.1 KB  |  256 lines  |  [TEXT/ttxt]

  1. OpenDoc™ Recipes
  2.  
  3.  
  4. Promises
  5. By The OpenDoc Design Team
  6. December 8, 1995.
  7.  
  8.  
  9. © 1993-1995  Apple Computer, Inc. All Rights Reserved.
  10. Apple, the Apple logo, AppleScript, Bento, Macintosh, QuickTime, and OpenDoc are 
  11. registered trademarks of Apple Computer, Inc.
  12. Finder, Mac, and QuickDraw are trademarks of Apple Computer, Inc. 
  13. SOM, SOMObjects, and System Object Model are licensed trademarks of IBM Corporation. 
  14.  
  15. Changes since DR3
  16.  
  17. • Added a recipe for forcing a promise to be fulfilled.
  18.  
  19. • Added use of the kODPropCloneKindUsed property to the recipe for fulfilling a promise.
  20.  
  21. Changes since DR2
  22.  
  23. 1) Fixed refcounting method names.
  24. 2) Fixed parameter passing errors with SetValue and GetValue.
  25.  
  26. Overview
  27.  
  28. The basic mechanisms for transfering data between Parts are the Clipboard and Drag-and-Drop. If the data to be exported is very big, the part may choose to export the data as a promise. When the data is retrieved by the destination part, the source part will be requested to fulfill the promise it put out.
  29.  
  30. The format of a Promise is determined by the Part. The only restriction is that a Promise must be able to be written to a Storage Unit Value.
  31.  
  32. Recipes
  33.  
  34. Putting out a promise:
  35.  
  36. The following code fragment shows how a Part can put out a Promise in response to a mouse down event and a Drag is going to be initiated. (This recipe can also be used to put out a promise to the Clipboard).
  37.  
  38. ODBoolean MyPartHandleDragging(MyPart* somSelf,
  39.                                     Environment* ev,
  40.                                     ODFacet* facet,
  41.                                     ODPoint where,
  42.                                     ODEventData event)
  43. {
  44.  
  45.     ........
  46.     // Get the ODDragAndDrop object from the session.
  47.  
  48.     ODDragAndDrop* dragAndDrop =
  49.             this->GetStorageUnit(ev)->GetSession(ev)->GetDragAndDrop(ev);
  50.  
  51.     // Reinitialize the ODDragAndDrop object.
  52.  
  53.     dragAndDrop->Clear(ev);
  54.  
  55.     // Get the Storage Unit where data for dragged objects is going to be     
  56.     // written.
  57.  
  58.     ODStorageUnit* storageUnit = dragAndDrop->GetContentStorageUnit(ev);
  59.  
  60.     // Focus the Storage Unit to the Property.
  61.  
  62.     storageUnit->Focus(ev,
  63.                             kODPropContents,
  64.                             kODPosUndefined,
  65.                             kODNULL,
  66.                             0,
  67.                             kODPosUndefined);
  68.  
  69.     // Prepare the promise. This section is Part specific.
  70.  
  71.     MyPromise    promise = .......
  72.  
  73.  // Put the promise data in an ODByteArray.
  74.  ODByteArray ba;
  75.  ...
  76.  
  77.     // Put out the promise.
  78.  
  79.     storageUnit->SetPromiseValue(
  80.                             ev,
  81.                             kAppleText,                                            // type of promised data
  82.                             0,                                                                                // offset
  83.                             &ba,                                                         // promise
  84.                             fPartWrapper);                                // source part
  85.  
  86.     // Initiate the Dragging
  87.     // Follow the drag and drop recipe.
  88.     .......
  89.  
  90. );
  91.  
  92. Getting Data From a Value with a Promise:
  93.  
  94. When the destination part retrieves the data (using ODStorageUnit::GetValue or ODStorageUnit::GetSize), the source part will be called to fulfill the promise. The destination part does not even know that the fulfilment of a promise is taking place.
  95.  
  96. The following is what the code for the destination part might look like. The same code is used whether the Value contains a promise or not.
  97.  
  98. ODDropResult YourPartDrop(YourPart* somSelf,
  99.                                 Environment* ev,
  100.                                 ODDragItemIterator* dropInfo,
  101.                                 ODFacet* facet,
  102.                                 ODPoint where)
  103.  
  104. {
  105.  
  106.     ODDropResult        dropResult = kODDropFail;
  107.     ODStorageUnit*    dropSU;
  108.     ODBoolean        notDone = kODTrue;
  109.  
  110.     // iterate through the types and find a desired type
  111.  
  112.     for (dropSU = dropInfo->First(ev);
  113.             dropInfo->IsNotComplete(ev) && notDone;
  114.             dropSU = dropInfo->Next(ev))
  115.     {
  116.         // If the desired type exists, import the data.
  117.  
  118.         if (dropSU->Exists(ev, kODPropContents, kAppleText, 0) == kODTrue) {
  119.  
  120.             // Focus to the property and value containing the desired data.
  121.  
  122.             dropSU->Focus(ev,
  123.                             kODPropContents,
  124.                             kODPosUndefined,
  125.                             kAppleText,
  126.                             0,
  127.                             kODPosUndefined);
  128.  
  129.             // Get the size of the data.
  130.  
  131.             // **** Note that the promise is being fulfilled here. But this Part
  132.             // **** does not even realize that.
  133.  
  134.             ODULong size = dropSU->GetSize(ev);
  135.  
  136.             // Create an ODByteArray to hold the returned data. The fields will be filled out by GetValue.
  137.             ODByteArray ba;
  138.  
  139.             storageUnit->GetValue(ev, size, &ba);
  140.  
  141.             // Put the data into the part’s content.
  142.  
  143.             ......
  144.  
  145.             // Dispose the byte array buffer.
  146.  
  147.             ODDisposePtr(ba._buffer);
  148.  
  149.             // Stop the iteration.
  150.  
  151.             notDone = kODFalse;
  152.  
  153.             // Set up drop result appropriately.
  154.  
  155.             dropResult = kODDropCopy;
  156.  
  157.         }
  158.  
  159.     }
  160.  
  161.     // Return the appropriate result code.
  162.  
  163.     return dropResult;
  164.  
  165. }
  166.  
  167. Fulfilling a Promise
  168.  
  169. The following code fragment is an example of what the source part might do in response to a request to fulfull a promise.
  170.  
  171. Parts must use the correct clone kind in their call to BeginClone when fulfilling a promise.  All parts should check for the presense of a kODPropCloneKindUsed property in the target storage unit.  If this property is present, the clone kind value there should be used; otherwise, kODCloneCopy should be used.  
  172.  
  173. (Parts that don't support linking don't have to worry about writing a kODPropCloneKindUsed property.  Parts that do support linking and embedding are referred to the Linking recipes for more information about the conditions when a part should write a kODPropCloneKindUsed property.)
  174.  
  175. void MyPartFulfillPromise(MyPart* somSelf,
  176.                                 Environment* ev,
  177.                                 ODStorageUnitView* promiseSUView)
  178.  
  179. {
  180.      // Do a check first to see whether it is the right size.
  181.      ODULong size = promiseSUView->GetSize(ev);
  182.  
  183.      if (size == sizeof(MyPromise))
  184.   {
  185.           // Get the Promise.
  186.           // Either GetValue or GetPromiseValue can be used here.
  187.           // OpenDoc ensures that if GetValue is used, there will be no infinite recursion
  188.           // (i.e., GetValue -> FulfillPromise -> GetValue -> FulFillPromise).
  189.  
  190.           // Set up the byte array for promise.
  191.           MyPromise    promise;
  192.           ODByeArray promiseByteArray;
  193.           promiseByteArray._length = promisedDataSize;
  194.           promiseByteArray._maximum = promisedDataSize;
  195.           promiseByteArray._buffer = &promise;
  196.  
  197.           promiseSUView->GetValue(ev, (ODValue) &promiseByteArray);
  198.  
  199.           // Get the Promised Data using the Promise.
  200.           // This section is part-specific.
  201.  
  202.           TempODPtr promisedData = ......(promise);    // automatically disposed
  203.  
  204.           // Determine the clone kind to use in cloning content to fulfill the promise
  205.           ODCloneKind cloneKind = kODCloneCopy;
  206.           ODStorageUnit* promiseSU = promiseSUView->GetStorageUnit(ev);
  207.           if ( ODSUExistsThenFocus(ev, promiseSU, kODPropCloneKindUsed, kODCloneKind) )
  208.                   cloneKind = ODGetULongProp(ev, promiseSU, kODPropCloneKindUsed, kODCloneKind);
  209.  
  210.     // Begin a clone transaction
  211.     // (Not necessary in this simple example because no objects are cloned,
  212.     // but this demonstrates the correct way to setup a cloning transaction.)
  213.     ODDraft* myDraft = somSelf->GetStorageUnit(ev)->GetDraft(ev);
  214.     ODDraftKey draftKey = 0;
  215.  
  216.     ODVolatile(myDraft);
  217.     ODVolatile(draftKey);
  218.  
  219.     draftKey = myDraft->BeginClone(ev, promiseSU->GetDraft(ev), kODNULL, cloneKind);
  220.  
  221.     TRY
  222.  
  223.                   // Set up the byte array for promisedData.
  224.                   ODByeArray promisedDataByteArray;
  225.                   promisedDataByteArray._length = promisedDataSize;
  226.                   promisedDataByteArray._maximum = promisedDataSize;
  227.                   promisedDataByteArray._buffer = promisedData;
  228.  
  229.                   // Write the promised data back to the Value.
  230.                   // One can use use the promiseSUView to get the Storage Unit and write out
  231.                   // other Properties and Values other than the one refered to by promiseSUView.
  232.                   promiseSUView->SetValue(ev, (ODValue) &promisedDataByteArray);
  233.  
  234.     CATCH_ALL
  235.  
  236.       myDraft->AbortClone(ev, draftKey);
  237.       RERAISE;
  238.  
  239.     ENDTRY
  240.  
  241.     myDraft->EndClone(ev, draftKey);
  242.      }
  243.      else
  244.   {
  245.           // Simply delete the promise.
  246.           promiseSUView->DeleteValue(ev, size);
  247.  
  248.           // The destination will simply see a Value with no content.
  249.           // It is the responsibility of the destination part to handle invalid values.
  250.           // This is no different from the general case without promises.
  251.      }
  252. }
  253.  
  254. Forcing Promise Fulfillment
  255.  
  256. There are times when your part might need to force the fulfillment of a promise it has written, before another part actually tries to read the data.  An example of this might be when your part takes some action that would prevent it from fulfilling the promise in the future.  The simplest way for a part to force a promise to be fulfilled is to focus on the promised property/value and call the storage unit routine GetSize.